/*! \file
 * \brief Enter a brief description here.
 *
 * Enter a detailed description here. (optional)
 * \author Author (Ivo Wingelaar)
 * \date Date (2011)
 * \version Version (0.0.1)
 * \copyright Copyright (GNU LGPL v3)
 */

#include "LynxOSManagerWindows_C.hpp"

#ifdef _LYNX_WINDOWS_

#include <windows.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

namespace Lynx
{

/** default constructor **/
OSManagerWindows_C::OSManagerWindows_C() :
    mOperatingSystem("")
{
    OSVERSIONINFOEX osvi;
    BOOL bOsVersionInfoEx;
    bool IsNonNTWindows;

    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
    if(!bOsVersionInfoEx)
    {
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        if(! GetVersionEx((OSVERSIONINFO *) &osvi))
            return;
    }

    switch(osvi.dwPlatformId)
    {
    case VER_PLATFORM_WIN32_NT:
        if(osvi.dwMajorVersion <= 4)
            mOperatingSystem.append("Microsoft Windows NT ");
        else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
            mOperatingSystem.append("Microsoft Windows 2000 ");
        else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
            mOperatingSystem.append("Microsoft Windows XP ");
        else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
            mOperatingSystem.append("Microsoft Windows Vista ");

        if(bOsVersionInfoEx)
        {
#ifdef VER_SUITE_ENTERPRISE
            if(osvi.wProductType == VER_NT_WORKSTATION)
            {
#ifndef __BORLANDC__
                if(osvi.wSuiteMask & VER_SUITE_PERSONAL)
                    mOperatingSystem.append("Personal ");
                else
                    mOperatingSystem.append("Professional ");
#endif
            }
            else if(osvi.wProductType == VER_NT_SERVER)
            {
                if(osvi.wSuiteMask & VER_SUITE_DATACENTER)
                    mOperatingSystem.append("DataCenter Server ");
                else if(osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
                    mOperatingSystem.append("Advanced Server ");
                else
                    mOperatingSystem.append("Server ");
            }
#endif
        }
        else
        {
            HKEY hKey;
            char szProductType[80];
            DWORD dwBufLen;

            RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                         __TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
                         0, KEY_QUERY_VALUE, &hKey);
            RegQueryValueEx(hKey, __TEXT("ProductType"), NULL, NULL,
                            (LPBYTE) szProductType, &dwBufLen);
            RegCloseKey(hKey);

            if(_strcmpi("WINNT", szProductType) == 0)
                mOperatingSystem.append("Professional ");
            if(_strcmpi("LANMANNT", szProductType) == 0)
                mOperatingSystem.append("Server ");
            if(_strcmpi("SERVERNT", szProductType) == 0)
                mOperatingSystem.append("Advanced Server ");
        }

        // Display version, service pack (if any), and build number.

        char tmp[255];

        if(osvi.dwMajorVersion <= 4)
            sprintf(tmp, "version %ld.%ld %s (Build %ld)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
        else
            sprintf(tmp, "%s (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);

        mOperatingSystem.append(tmp);
        break;

    case VER_PLATFORM_WIN32_WINDOWS:
        IsNonNTWindows = true;

        if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
        {
            mOperatingSystem.append("Microsoft Windows 95 ");
            if(osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B')
                mOperatingSystem.append("OSR2 ");
        }

        if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
        {
            mOperatingSystem.append("Microsoft Windows 98 ");
            if(osvi.szCSDVersion[1] == 'A')
                mOperatingSystem.append("SE ");
        }

        if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
            mOperatingSystem.append("Microsoft Windows Me ");

        break;

    case VER_PLATFORM_WIN32s:
        IsNonNTWindows = true;
        mOperatingSystem.append("Microsoft Win32s ");
        break;
    }
}

/** default destructor **/
OSManagerWindows_C::~OSManagerWindows_C()
{
    //
}

/** const virtual function **/
/** get_os_version         **/
//! Returns a string containing the name and the version of the os.
/// \return std::string
///         A string containing the name and the version of the os.
/// \param  void
std::string OSManagerWindows_C::get_os_version(void) const
{
    return mOperatingSystem.c_str();
}

/** const virtual function **/
/** copy_to_clipboard      **/
//! Copies a string the to clipboard.
/// \return void
/// \param    const std::string& str
///         The string you want to copy to the clipboard.
void OSManagerWindows_C::copy_to_clipboard(const std::string& str) const
{
    if(!OpenClipboard(NULL) || str == 0)
        return;

    EmptyClipboard();

    HGLOBAL clipbuffer;
    char* buffer;

    clipbuffer = GlobalAlloc(GMEM_DDESHARE, strlen(str)+1);
    buffer = (char*)GlobalLock(clipbuffer);

    strcpy(buffer, str);

    GlobalUnlock(clipbuffer);
    SetClipboardData(CF_TEXT, clipbuffer);
    CloseClipboard();
}

/** const virtual function **/
/** get_from_clipboard     **/
//! Returns a string from the clipboard.
/// \return std::string
///         A string from the clipboard.
/// \param  void
std::string OSManagerWindows_C::get_from_clipboard(void) const
{
    if(!OpenClipboard(NULL))
        return 0;

    char* buffer = 0;

    HANDLE hData = GetClipboardData(CF_TEXT);
    buffer = (char*)GlobalLock(hData);
    GlobalUnlock(hData);
    CloseClipboard();
    return buffer;
}

/** const virtual function  **/
/** get_processor_speed_mhz **/
//! Returns the processor speed in MHz.
/// \return bool
///         True if the call succeeded, false otherwise.
/// \param    uint32_t& mhz
///         The speed in mhz.
bool OSManagerWindows_C::get_processor_speed_mhz(uint32_t& mhz) const
{
    LONG Error;
    HKEY Key;
    Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                         __TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
                         0, KEY_READ, &Key);

    if(Error != ERROR_SUCCESS)
        return false;

    DWORD Speed = 0;
    DWORD Size = sizeof(Speed);
    Error = RegQueryValueEx(Key, __TEXT("~MHz"), NULL, NULL, (LPBYTE)&Speed, &Size);

    RegCloseKey(Key);

    if(Error != ERROR_SUCCESS)
        return false;
    else if(mhz)
        *mhz = Speed;
    return true;
}

/** const virtual function **/
/** get_processor_count    **/
//! Returns the number of processors.
/// \return bool
///         True if the call succeeded, false otherwise.
/// \param    uint32_t& count
///         The number of processors.
bool OSManagerWindows_C::get_processor_count(uint32_t& count) const
{
    return false;
}

/** const virtual function **/
/** get_system_memory      **/
//! Returns a few stats on ram-memory.
/// \return bool
///         True if the call succeeded, false otherwise.
/// \param    uint32_t* total
///         The total amount of ram installed.
/// \param    uint32_t* available
///         The amount of ram available.
bool OSManagerWindows_C::get_system_memory(uint32_t* total,
        uint32_t* available) const
{
    MEMORYSTATUS MemoryStatus;
    MemoryStatus.dwLength = sizeof(MEMORYSTATUS);

    // cannot fail
    GlobalMemoryStatus(&MemoryStatus);

    if(total)
        *total = (uint32_t)(MemoryStatus.dwTotalPhys>>10);
    if(available)
        *available = (uint32_t)(MemoryStatus.dwAvailPhys>>10);

    return true;
}

} // namespace Lynx

#endif // _LYNX_WINDOWS_
